﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Drawing;
using System.IO;

namespace KinectDrawer
{
    class UserDrawing
    {
        private List<List<System.Drawing.Point>> dataDrawing;
        private WriteableBitmap drawingBitmap;
        private int width, height;
        public UserDrawing(int width, int height)
        {
            dataDrawing = new List<List<System.Drawing.Point>>();
            drawingBitmap = new WriteableBitmap(width, height, 96.0, 96.0, PixelFormats.Bgr32, null);
            this.width = width;
            this.height = height;
            MAX_DISTANCE_BETWEEN_POINTS = (width + height) / 10;
        }

        public List<List<System.Drawing.Point>> GetRawData() { return dataDrawing; }

        public void Clear()
        {
            dataDrawing.Clear();
        }

        public bool IsEmpty { get { return (dataDrawing.Count == 0); } }

        //Distance maximale entre deux points pour accepter un nouveau point dans le point de la ligne entre la distance du point
        private int MAX_DISTANCE_BETWEEN_POINTS;

        public void AddPoint(System.Drawing.Point point, bool isNewLine)
        {
            if (isNewLine)
            {
                List<System.Drawing.Point> line = new List<System.Drawing.Point>();
                line.Add(point);
                dataDrawing.Add(line);
            }
            else
            {
                List<System.Drawing.Point> lastLine;
                if (dataDrawing.Count > 0)
                {
                    lastLine = dataDrawing[dataDrawing.Count - 1];
                    System.Drawing.Point lastPoint = lastLine[lastLine.Count - 1];
                    double distanceBetweenPoints = Math.Round(Math.Sqrt(Math.Pow((lastPoint.X - point.X), 2) + Math.Pow((lastPoint.Y - point.Y), 2)), 1);
                    if (distanceBetweenPoints < MAX_DISTANCE_BETWEEN_POINTS)
                    {
                        lastLine.Add(point);
                    }
                    else
                    {
                        Console.WriteLine("Detection point is too faaar away");
                    }
                } else
                {
                    lastLine = new List<Point>();
                    lastLine.Add(point);
                } 

                //Si le nouveau point est trop loin du dernier enregistré, on le skippe
                
            }
        }

        public BitmapSource PrintDrawingOnBitmap(BitmapSource cameraBitmapSource)
        {
            BitmapSource userDrawingBitmapSource = this.ToImage();

            //On récupère les deux bitmaps (camera et userdrawing)
            Bitmap cameraImage = BitmapFromSource(cameraBitmapSource);
            Bitmap userDrawingBitmap = BitmapFromSource(userDrawingBitmapSource);

            //On transforme le noir de userdrawing en transparent
            userDrawingBitmap.MakeTransparent(System.Drawing.Color.Black);

            //On crée un graphics qui pointe sur l'image de la camera
            var graphics = Graphics.FromImage(cameraImage);
            graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;

            //On y ajoute l'image d'userdrawing
            graphics.DrawImage(userDrawingBitmap, 0, 0);

            //Reconversion en bitmapsource
            MemoryStream ms = new MemoryStream();
            cameraImage.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
            ms.Position = 0;
            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            bi.StreamSource = ms;
            bi.EndInit();

            return bi;
        }

        private System.Drawing.Bitmap BitmapFromSource(BitmapSource bitmapsource)
        {
            System.Drawing.Bitmap bitmap;
            using (MemoryStream outStream = new MemoryStream())
            {
                BitmapEncoder enc = new BmpBitmapEncoder();
                enc.Frames.Add(BitmapFrame.Create(bitmapsource));
                enc.Save(outStream);
                bitmap = new System.Drawing.Bitmap(outStream);
            }
            return bitmap;
        }

        public BitmapSource ToImage()
        {
            //Initialise la bitmap
            Bitmap bmp = new Bitmap(width, height);
            Graphics graphics = Graphics.FromImage(bmp);
            System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Brushes.Orange, 12);

            //Crée les lignes entre les points
            List<System.Drawing.Point>[] myLines = dataDrawing.ToArray();
            foreach (List<System.Drawing.Point> currentLine in myLines)
            {
                for (int i = 0; i < currentLine.Count - 1; i++)
                {
                    graphics.DrawLine(pen, currentLine[i], currentLine[i + 1]);
                }
            }
            return convertBitmapToBitmapSource(bmp);
        }

        private BitmapSource convertBitmapToBitmapSource(Bitmap bmp)
        {
            //Draw bitmap
            MemoryStream ms = new MemoryStream();
            bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
            ms.Position = 0;
            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            bi.StreamSource = ms;
            bi.EndInit();
            return bi;
        }
    }
}
